package com.itcoon.cloud.framework.webmvc.converter;/**
 * @author Athric Yu
 * 2024/11/11
 **/

import com.fasterxml.jackson.databind.type.TypeFactory;
import com.itcoon.cloud.framework.enums.BasicEnum;
import com.itcoon.cloud.framework.enums.ValueEnum;
import com.itcoon.cloud.framework.utils.ClassUtil;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.util.ReflectionUtils;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.function.Function;

/**
 *
 *
 * @author Athric Yu
 * 2024/11/11
 **/
public class ValueEnumConverterFactory<V extends Serializable, E extends Enum<E> & ValueEnum<V, E>> implements ConverterFactory<String, E> {

    @Override
    public <T extends E> Converter<String, T> getConverter(Class<T> targetType) {
        Type baseInterface = ClassUtil.findGenericInterfaceTypeByClass(targetType, BasicEnum.class);
        ParameterizedType parameterizedType = (ParameterizedType) baseInterface;
        // 获取具体的枚举类型
        Type targetActualTypeArgument = parameterizedType.getActualTypeArguments()[1];
        Class<?> targetAawArgument = TypeFactory.defaultInstance()
                .constructType(targetActualTypeArgument).getRawClass();
        // 判断是否实现自通用枚举
        if (BasicEnum.class.isAssignableFrom(targetAawArgument)) {
            // 获取父接口的泛型类型
            Type valueArgument = parameterizedType.getActualTypeArguments()[0];
            // 获取值的class
            Class<V> valueRaw = (Class<V>) TypeFactory.defaultInstance()
                    .constructType(valueArgument).getRawClass();

            String valueOfMethod = "valueOf";
            // 转换入参的类型
            Method valueOf = ReflectionUtils.findMethod(valueRaw, valueOfMethod, String.class);
            if (valueOf != null) {
                ReflectionUtils.makeAccessible(valueOf);
            }
            // 将String类型的值转为枚举值对应的类型
            Function<String, V> castValue =
                    // 获取不到转换方法时直接返回null
                    source -> {
                        if (valueRaw.isInstance(source)) {
                            // String类型直接强转
                            return valueRaw.cast(source);
                        }
                        // 其它包装类型使用valueOf转换
                        return valueOf == null ? null
                                : (V) ReflectionUtils.invokeMethod(valueOf, valueRaw, source);
                    };
            return source -> ValueEnum.fromValue(castValue.apply(source), targetType);
        }
        return source -> null;
    }
}
